#pragma once
#include "SehnsuchtReaderWriter.hxx"

namespace Sehnsucht { namespace IO { 
	ref_class_decl BasicLoader
	{

#ifndef REIGN_PHONE // !Phone
		typedef IWICImagingFactory2 WicFactory2;
		TinyTypeDecl( WicFactory2 );
#endif // All

		typedef D3D11_INPUT_ELEMENT_DESC DirectXInputElementDesc; TinyTypeDecl(DirectXInputElementDesc);
		typedef ID3D11ShaderResourceView ShaderResourceView; TinyTypeDecl(ShaderResourceView);
		typedef ID3D11GeometryShader GeometryShader; TinyTypeDecl(GeometryShader);
		typedef ID3D11ComputeShader ComputeShader; TinyTypeDecl(ComputeShader);
		typedef ID3D11DomainShader DomainShader; TinyTypeDecl(DomainShader);
		typedef ID3D11VertexShader VertexShader; TinyTypeDecl(VertexShader);
		typedef ID3D11PixelShader PixelShader; TinyTypeDecl(PixelShader);
		typedef ID3D11HullShader HullShader; TinyTypeDecl(HullShader);
		typedef ID3D11InputLayout InputLayout; TinyTypeDecl(InputLayout);
		typedef ID3D11Texture2D Texture2; TinyTypeDecl(Texture2);
		typedef ID3D11Resource Resource; TinyTypeDecl(Resource);
		typedef BasicReaderWriter Reader;
		typedef ID3D11Device1 Device3;

#ifdef REIGN_DESKTOP // Desktop
		typedef Reign::Standard::String16 StringArg; TinyTypeDecl( StringArg );
		typedef std::shared_ptr<Reader> UniquePtrReader;
		TinyTypeDecl( UniquePtrReader );
#else // Nondesktop
		typedef Platform::String^ StringArg;
		typedef Reader^ UniquePtrReader;
#endif // All

		typedef Concurrency::task<Void> AsyncAction;
		typedef Void Action;

		TinyTypeDecl( AsyncAction );
		TinyTypeDecl( Device3 );

	private:

		// Members and closed functionality 

#ifndef REIGN_PHONE
		Microsoft::WRL::ComPtr<WicFactory2> m_WicFactory; // Used for creating the resources from memory. 
#endif
		Device3Ptr m_Device; // Used for creating the resources from memory. 
		UniquePtrReader m_Reader; // Used for reading the resources from files on disk. 

		StringArg GetExtension( 
			_In_ StringArg wszFileName 
			);

		Action CreateTexture(
			_In_ Bool bDecodeAsDDS,
			_In_reads_bytes_(uDataSize) BytePtr pData,
			_In_ UInt32 uDataSize,
			_Outptr_result_nullonfailure_ Texture2Address ppTexture,
			_Outptr_opt_result_nullonfailure_ ShaderResourceViewAddress ppView,
			_In_opt_ StringArg wszDebugName
			);

		Action CreateInputLayout(
			_In_reads_bytes_(uBytecodeSize) BytePtr pBytecode,
			_In_ UInt32 uBytecodeSize,
			_In_reads_opt_(uLayoutDescNumElements) DirectXInputElementDescPtr pLayoutDescElements,
			_In_ UInt32 uLayoutDescNumElements,
			_Outptr_opt_result_nullonfailure_ InputLayoutAddress ppLayout,
			_In_opt_ StringArg wszDebugName
			);

	internal:

#ifndef REIGN_PHONE
		BasicLoader(
			_In_ Device3Ptr pDevice,
			_In_ WicFactory2Ptr pFactory = nullptr
			);
#else
		BasicLoader(
			_In_ Device3Ptr pDevice
			);
#endif

		// Sync methods 

		Action LoadTexture(
			_In_ StringArg wszFileName, 
			_Outptr_result_nullonfailure_ Texture2Address ppTexture,
			_Outptr_opt_result_nullonfailure_ ShaderResourceViewAddress ppView
			);
		Action LoadShader(
			_In_ StringArg wszFileName,
			_In_reads_opt_(layoutDescNumElements) D3D11_INPUT_ELEMENT_DESC pLayoutDescElements[],
			_In_ UInt32 uLayoutDescNumElements,
			_Outptr_result_nullonfailure_ VertexShaderAddress ppShader,
			_Outptr_opt_result_nullonfailure_ InputLayoutAddress ppLayout
			);
		Action LoadShader(
			_In_ StringArg wszFileName,
			_In_reads_opt_(uNumEntries) const D3D11_SO_DECLARATION_ENTRY streamOutDeclaration[],
			_In_ UInt32 uNumEntries,
			_In_reads_opt_(uNumStrides) const UInt32 pBufferStrides[],
			_In_ UInt32 uNumStrides,
			_In_ UInt32 uRasterizedStream,
			_Outptr_result_nullonfailure_ GeometryShaderAddress ppShader
			);
		Action LoadShader(
			_In_ StringArg wszFileName,
			_Outptr_result_nullonfailure_ HullShaderAddress ppShader
			);
		Action LoadShader(
			_In_ StringArg wszFileName,
			_Outptr_result_nullonfailure_ DomainShaderAddress ppShader
			);
		Action LoadShader(
			_In_ StringArg wszFileName,
			_Outptr_result_nullonfailure_ GeometryShaderAddress ppShader
			);
		Action LoadShader(
			_In_ StringArg wszFileName,
			_Outptr_result_nullonfailure_ PixelShaderAddress ppShader
			);
		Action LoadShader(
			_In_ StringArg wszFileName,
			_Outptr_result_nullonfailure_ ComputeShaderAddress ppShader
			);

		// Async methods 
	
		AsyncAction LoadTextureAsync(
			_In_ StringArg wszFileName, 
			_Outptr_opt_result_nullonfailure_ Texture2Address ppTexture,
			_Outptr_opt_result_nullonfailure_ ShaderResourceViewAddress ppView
			);
		AsyncAction LoadShaderAsync(
			_In_ StringArg wszFileName,
			_In_reads_opt_(layoutDescNumElements) D3D11_INPUT_ELEMENT_DESC pLayoutDescElements[],
			_In_ UInt32 uLayoutDescNumElements,
			_Outptr_result_nullonfailure_ VertexShaderAddress ppShader,
			_Outptr_opt_result_nullonfailure_ InputLayoutAddress ppLayout
			);
		AsyncAction LoadShaderAsync(
			_In_ StringArg wszFileName,
			_In_reads_opt_(uNumEntries) const D3D11_SO_DECLARATION_ENTRY pStreamOutDeclaration[],
			_In_ UInt32 uNumEntries,
			_In_reads_opt_(uNumStrides) const UInt32 pBufferStrides[],
			_In_ UInt32 uNumStrides,
			_In_ UInt32 uRasterizedStream,
			_Outptr_result_nullonfailure_ GeometryShaderAddress ppShader
			);
		AsyncAction LoadShaderAsync(
			_In_ StringArg wszFileName,
			_Outptr_result_nullonfailure_ HullShaderAddress ppShader
			);
		AsyncAction LoadShaderAsync(
			_In_ StringArg wszFileName,
			_Outptr_result_nullonfailure_ DomainShaderAddress ppShader
			);
		AsyncAction LoadShaderAsync(
			_In_ StringArg wszFileName,
			_Outptr_result_nullonfailure_ GeometryShaderAddress ppShader
			);
		AsyncAction LoadShaderAsync(
			_In_ StringArg wszFileName,
			_Outptr_result_nullonfailure_ PixelShaderAddress ppShader
			);
		AsyncAction LoadShaderAsync(
			_In_ StringArg wszFileName,
			_Outptr_result_nullonfailure_ ComputeShaderAddress ppShader
			);

	}; // Loader

}; }; // Sehnsucht IO